
`include "common_header.verilog"

//  *************************************************************************
//  File : p8264_pcs_mld_rx.v
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2009 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Denis Poverennyy
//  info@morethanip.com
//  *************************************************************************
//  Description : 40G/64 bits PCS  (Descrambler + Decoder + optional EEE) 
//  plus MLD
//  Version     : $Id: p8264_pcs_mld_rx.v,v 1.12 2016/07/13 06:58:13 dk Exp $
//  *************************************************************************


module p8264_pcs_mld_rx (

        reset_rxclk,
        cgmii_rxclk,     
        sw_reset,        
        signal_det,      
        cgmii_txc,       
        cgmii_txd,       
        cgmii_txclk_ena, 
        cgmii_rxc,       
        cgmii_rxd,       
        xlgmii_rxt0_next,                         
        cgmii_rxclk_ena, 
        scr_bypass,
        ena_clause49,
        ena_hi_ber25,
        disable_mld,
        loopback_ena,    
        ber_count_read,  
        err_block_cnt_rd,
        r_test_mode,     
        en_chk_pat49,
        sel_pat,
        pat_err_cnt_rd,          
        block_lock_in,
        desk_buf_0_data, 
        desk_buf_1_data, 
        desk_buf_2_data, 
        desk_buf_3_data, 
        desk_buf_rd_vec,         
        desk_buf_full,   
        desk_buf_aempty,
        desk_buf_empty,          
        mld_rst,         
        mld_rst_done,    
        lane_active,
        block_lock,      
        align_lock,      
        align_lock_l,    
        hi_ber,          
        vl_intvl,        
        vl_0_enc,        
        vl_1_enc,        
        vl_2_enc,        
        vl_3_enc,                
        ber_timer_short, 
        ber_timer_done,  
        lane_map,        
        err_block_cnt,   
        ber_count,       
        pat_err_cnt,     
        bip8_err_stat_0, 
        bip8_err_stat_1, 
        bip8_err_stat_2, 
        bip8_err_stat_3 

`ifdef MTIPPCS82_EEE_ENA
        ,
        lpi_tick,		                                
        lpi_fw,                                                                                 
        scr_bypass_enable,                                                                      
        energy_detect,		
        rx_lpi_active,                                          
        rx_lpi_mode,                                                    
        rx_lpi_state,           
        rx_fw_state,		                
        wake_error_counter_inc,                                                                 
        fec_fastlock,
        ram_period      
`endif                  

);

`include "mtip_pcs100g_pack_package.verilog"

input           reset_rxclk;            // async active high reset
input           cgmii_rxclk;            // system clock
input           sw_reset;               // Software Reset
input   [3:0]   signal_det;             // if low SERDES' signals are not valid
input   [7:0]   cgmii_txc;              // XL/CGMII transmit control
input   [63:0]  cgmii_txd;              // XL/CGMII transmit data
input           cgmii_txclk_ena;        // XL/CGMII transmit clock enable
output  [7:0]   cgmii_rxc;              // XL/CGMII receive control
output  [63:0]  cgmii_rxd;              // XL/CGMII receive data
output          xlgmii_rxt0_next;       // Advance indication if TERM block without data is next after current 
                                        // directly from decoder classification block type 0x87, T0)   
output          cgmii_rxclk_ena;        // XL/CGMII receive clock enable
input           scr_bypass;             // bypass scrambling and descrambling within PCS
input  	        ena_clause49;           // Enable Clause 49 (1) or Clause 82 (0) PCS encoder/decoder 
input           disable_mld;            // Disable MLD (10G/25G mode setting)
input           ena_hi_ber25;           // Enable Hi-Ber Measure Interval for 25G Mode
input           loopback_ena;           // Loopback Enable
input           ber_count_read;         // BER_count counters have been read
input           err_block_cnt_rd;       // Block error counter has been read
input           r_test_mode;            // Receive test pattern mode
input           en_chk_pat49;           // Enable 10G Test pattern checker (49.2.12) 
input           sel_pat;                // Select pattern : 1 => 00 / 0 => Local Fault 
input           pat_err_cnt_rd;         // test pattern error counter has been read
input   [3:0]   block_lock_in;          // true block lock from block sync module, copied already into cgmii_rxclk domain.
input   [66:0]  desk_buf_0_data;        // buffer 0 data
input   [66:0]  desk_buf_1_data;        // buffer 1 data
input   [66:0]  desk_buf_2_data;        // buffer 2 data
input   [66:0]  desk_buf_3_data;        // buffer 3 data
output  [3:0]   desk_buf_rd_vec;        // read from the deskew buffer (one bit per buffer)

input   [3:0]   desk_buf_full;          // deskew buffer full in ref domain
input   [3:0]   desk_buf_aempty;        // deskew buffer almost empty in ref domain
input   [3:0]   desk_buf_empty;         // deskew buffer empty in ref domain


output          mld_rst;                //  mld reset for serdes clock domain blocks
input   [3:0]   mld_rst_done;           //  mld reset from serdes clock domain blocks    
input   [3:0]   lane_active;		//  Current active lanes


output          block_lock;             // Block lock state reached
output          align_lock;             // Alignment marker lock state reached
output   [3:0]  align_lock_l;           // Alignment marker lock state reached per VL
output          hi_ber;                 // High Bit Error
input   [15:0]  vl_intvl;               // Virtual Lane Marker Interval Setting        
input   [23:0]  vl_0_enc;               // Marker pattern for PCS Virtual Lane 0
input   [23:0]  vl_1_enc;               // Marker pattern for PCS Virtual Lane 1
input   [23:0]  vl_2_enc;               // Marker pattern for PCS Virtual Lane 2
input   [23:0]  vl_3_enc;               // Marker pattern for PCS Virtual Lane 3

input           ber_timer_short;        // speed up for test mode
output          ber_timer_done;         // Hi BER measure window 
output   [7:0]  lane_map;               // Lane mapping status
output   [21:0] err_block_cnt;          // Block error counter to be read
output   [21:0] ber_count;              // BER_count counter to be read
output   [15:0] pat_err_cnt;            // test pattern error counter
output          bip8_err_stat_0;        // BIP-8 error status lane 0
output          bip8_err_stat_1;        // BIP-8 error status lane 1
output          bip8_err_stat_2;        // BIP-8 error status lane 2
output          bip8_err_stat_3;        // BIP-8 error status lane 3 

`ifdef MTIPPCS82_EEE_ENA 

input  		lpi_tick;		// A timer tick, which asserts for one reference clock (ref_clk) cycle in average every 100ns.
input           lpi_fw;                 // 1 when the link is to use the fast wake mechanism, else use deep sleep mechanism for each direction.
input           scr_bypass_enable;      // Indicate to the LPI state diagram that the scrambler bypass option is required.
input	        energy_detect;		// Indication from Serdes that it detects signaling at its input					
output          rx_lpi_active;          // A Boolean variable that is set to true when the receiver is in a low power state. 
output          rx_lpi_mode;            // A variable reflecting state of the LPI receive function (Figure 82-17): DATA (0) and QUIET (1).
output  [2:0]   rx_lpi_state;           // A variable reflecting state of the LPI SM as described by the LPI transmit state  diagram (Figure 82-17).
output          rx_fw_state;		// Indicates that the RX SM in the RX_FW state
output          wake_error_counter_inc; // To increment the Wake Error Counter each time that the LPI receive state diagram enters the RX_WTF
output          fec_fastlock;           // if set, allows fast FEC lock acquisition procedure. The signal set when LPI SM in the RX_WAKE state
output          ram_period;             // if set the RAM is expected;

`endif                                  

//-------------------------------------
// Output Signals
//-------------------------------------

wire    [7:0]   cgmii_rxc;              
wire    [63:0]  cgmii_rxd;              
wire            xlgmii_rxt0_next;       
wire            cgmii_rxclk_ena;        
wire    [3:0]   desk_buf_rd_vec;        



wire            mld_rst;                
wire            block_lock;             
wire            align_lock;             
wire     [3:0]  align_lock_l;           
wire            hi_ber;                 
wire            ber_timer_done;         
wire     [7:0]  lane_map;               
wire     [21:0] err_block_cnt;          
wire     [21:0] ber_count;              
wire     [15:0] pat_err_cnt;            
wire            bip8_err_stat_0;        
wire            bip8_err_stat_1;        
wire            bip8_err_stat_2;        
wire            bip8_err_stat_3;        

`ifdef MTIPPCS82_EEE_ENA 
wire            rx_lpi_active;
wire            rx_lpi_mode;
wire    [2:0]   rx_lpi_state;
wire            rx_fw_state;
wire            fec_fastlock;
wire            ram_period;
`endif                                  

//-------------------------------------
// Internal Signals
//-------------------------------------

wire            dsc_rxclk_ena;          // from MLD to descrambler
wire    [1:0]   dsc_tin_0;              // sync header from MLD to descrambler
wire    [63:0]  dsc_din_0;              // 64 bit block from MLD to descrambler
wire            dec_block_lock;         // block lock to decoder
wire            align_lock_int;         // Align lock (ANDered all align lock per lock) 
wire            hi_ber_int;             // Hi BER detected 
wire    [3:0]   bip8_err;               // Bip error per lane    
wire            rx_block_lock;          // Anded block lock from the serdes block  
    
`ifdef MTIPPCS82_EEE_ENA 

wire            rx_lpi_active_int;

wire            r_type_li;              // LPI Block Received
wire            r_type_c;               // C block Received
wire            r_type_val;             // valid signal for r_type_li and r_type_c

wire            first_rx_lpi_active;    // first change from RX_ACTIVE into any LPI state
wire    [7:0]   rx_down_count;          // current down counter
wire            rx_down_count_val;      // if 1, the rx_down_count is valid  
wire            mld_start;              // mld reorder starts as soon as deskew fifo not empty
wire            align_lock_eee;         // align lock in the Low Power mode 
wire            sw_reset_eee;           // ored normal reset with eee reset (power up was not successful)
wire            eee_link_fail_rst;      // RX_LINK_FAIL state reached

`endif

wire [3:0] mld_block_lock;
reg  [2:0] block_lock_s;

p8264_mld_rx_top MLD_RX_TOP (	
        .reset_rxclk            (reset_rxclk),          
        .cgmii_rxclk            (cgmii_rxclk),          

`ifdef MTIPPCS82_EEE_ENA
        .sw_reset               (sw_reset_eee),         
`else
        .sw_reset               (sw_reset),             
`endif

        .desk_buf_0_data        (desk_buf_0_data),      
        .desk_buf_1_data        (desk_buf_1_data),      
        .desk_buf_2_data        (desk_buf_2_data),      
        .desk_buf_3_data        (desk_buf_3_data),      
        .desk_buf_rd            (),        
        .desk_buf_rd_vec        (desk_buf_rd_vec),      
        .mld_rst                (mld_rst),              
        .mld_rst_done           (mld_rst_done),         
        .ena_hi_ber25           (ena_hi_ber25),
        .disable_mld            (disable_mld),
        .lane_active		(lane_active),       
        .vl_intvl               (vl_intvl),
        .vl_0_enc               (vl_0_enc),
        .vl_1_enc               (vl_1_enc),
        .vl_2_enc               (vl_2_enc),
        .vl_3_enc               (vl_3_enc),
        .signal_det             (signal_det),
`ifdef MTIPPCS82_EEE_ENA 
        .ram_period             (ram_period),
        .first_rx_lpi_active    (first_rx_lpi_active),
        .rx_lpi_active          (rx_lpi_active_int),
        .rx_down_count          (rx_down_count),
        .rx_down_count_val      (rx_down_count_val),
        .mld_start              (mld_start),
`endif 
        .loopback_ena           (loopback_ena),         
        .cgmii_txclk_ena        (cgmii_txclk_ena),      
        .block_lock             (mld_block_lock),       
        .desk_buf_full          (desk_buf_full),              
        .desk_buf_aempty        (desk_buf_aempty),
        .desk_buf_empty         (desk_buf_empty),       
        .data_val               (dsc_rxclk_ena),        
        .data_type              (dsc_tin_0),            
        .data_out               (dsc_din_0),            
        .lane_map               (lane_map),             
        .align_done             (align_lock_int),       
        .align_done_l           (align_lock_l),         
        .bip8_err               (bip8_err),             
        .ber_timer_short        (ber_timer_short),
        .ber_timer_done         (ber_timer_done),
        .ber_count_read         (ber_count_read),       
        .r_test_mode            (r_test_mode),          
        .hi_ber                 (hi_ber_int),           
        .ber_count              (ber_count));           
          
          
          
assign bip8_err_stat_0 = bip8_err[0]; 
assign bip8_err_stat_1 = bip8_err[1]; 
assign bip8_err_stat_2 = bip8_err[2]; 
assign bip8_err_stat_3 = bip8_err[3];


always @(posedge reset_rxclk or posedge cgmii_rxclk)
begin
        if (reset_rxclk == 1'b 1)
        begin
                block_lock_s <= 3'b 000;	
        end
        else
        begin
        //1D scrambler+1D Decoder+1D clk ena out
        block_lock_s <= {block_lock_s[1:0], mld_block_lock[0]};
        
        end
end
 
 // ---------------------------------------
// Descrambler to Decode and pattern check
// ---------------------------------------

assign  dec_block_lock = disable_mld == 1'b 1 ? block_lock_s[2] :       // ensure decoder is getting enabled.
                        `ifdef MTIPPCS82_EEE_ENA
                         align_lock_eee
                        `else
                         align_lock_int
                        `endif
                        ;


decode64_dp U_DECODEDP (

        .reset                  (reset_rxclk),
        .clk                    (cgmii_rxclk),
        .clk_ena                (dsc_rxclk_ena),
        .data_0_in              (dsc_din_0),             // from MLD to descrambler
        .sh_0_in                (dsc_tin_0),
        .scr_bypass             (scr_bypass),           // bypass scrambling and descrambling within PCS
        .ena_clause49           (ena_clause49),
        .loopback_ena           (loopback_ena),
        .cgmii_txclk_ena        (cgmii_txclk_ena),
        .cgmii_txc              (cgmii_txc),
        .cgmii_txd              (cgmii_txd),
`ifdef MTIPPCS82_EEE_ENA
        .rx_lpi_active          (rx_lpi_active_int),
        .r_type_li              (r_type_li),              
        .r_type_c               (r_type_c),
        .r_type_val             (r_type_val),
`endif
        .r_test_mode            (r_test_mode),
        .en_chk_pat49           (en_chk_pat49),
        .sel_pat                (sel_pat),
        .block_lock             (dec_block_lock),
        .hi_ber                 (hi_ber_int),
        .err_block_count_rd     (err_block_cnt_rd),
        .err_block_count        (err_block_cnt),
        .pat_err_cnt_rd         (pat_err_cnt_rd),
        .pat_err_cnt            (pat_err_cnt),
        .rx_d_out               (cgmii_rxd),
        .rx_c_out               (cgmii_rxc),
        .xlgmii_rxt0_next       (xlgmii_rxt0_next),
        .rx_val_out             (cgmii_rxclk_ena));  // use decoder as pipeline


// unmasked block lock from lane(s)

assign rx_block_lock = disable_mld == 1'b 1 ? block_lock_in[0] :        // single lane only
                       (block_lock_in[3] & block_lock_in[2] & block_lock_in[1] & block_lock_in[0]);


`ifdef MTIPPCS82_EEE_ENA 

assign rx_lpi_active = rx_lpi_active_int;       // out wire

// if ram not found yet, the deskew buffers are not valid yet

assign align_lock_eee = (ram_period == 1'b0)? align_lock_int :  align_lock_int & mld_start;

assign sw_reset_eee = sw_reset | eee_link_fail_rst;

p824964_eee_ctl_rx U_EEECTLRX (

        .reset                  (reset_rxclk),                  
        .clk                    (cgmii_rxclk),                    
        .sw_reset               (sw_reset),
        .disable_mld            (disable_mld),

        // link status

        .rx_block_lock          (rx_block_lock),          
        .rx_align_status        (align_lock_int),        
        .block_lock             (block_lock),             
        .align_status           (align_lock),

        // from decoder

        .r_type_li              (r_type_li),              
        .r_type_c               (r_type_c),               
        .r_type_val             (r_type_val),

        // EEE controls
        
        .lpi_tick               (lpi_tick),		                                
        .lpi_fw                 (lpi_fw),                                                                                 
        .scr_bypass_enable      (scr_bypass_enable),                                                                      
        .energy_detect          (energy_detect),                  
        .rx_lpi_active          (rx_lpi_active_int),            // local                                         
        .rx_lpi_mode            (rx_lpi_mode),                                                    
        .rx_lpi_state           (rx_lpi_state),           
        .rx_fw_state            (rx_fw_state),		                
        .wake_error_counter_inc (wake_error_counter_inc),                                                                 
        .fec_fastlock           (fec_fastlock),                

        // down-counter

        .ram_period             (ram_period),
        .first_rx_lpi_active    (first_rx_lpi_active),
        .eee_link_fail_rst      (eee_link_fail_rst),
        .rx_down_count          (rx_down_count),
        .rx_down_count_val      (rx_down_count_val)

);


`else

//  Receive Status
// 
assign align_lock = align_lock_int; 

assign block_lock = rx_block_lock; 


`endif

assign hi_ber = hi_ber_int; 

endmodule // module p8264_pcs_mld_rx